package com.sgcc.pda.bluetooth.bt;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.Environment;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.UUID;

/**
 * 客户端和服务端的基类，用于管理socket长连接
 */
public class BtBase {

    private final static String TAG = "BtBase";

    private static final String FILE_PATH =
            Environment.getExternalStorageDirectory().getAbsolutePath() + "/com.sgcc.pda.bluetooth/";

    static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
    private static final int FLAG_MSG = 0;  //消息标记
    private static final int FLAG_FILE = 1; //文件标记

    private BluetoothSocket mSocket;
    private DataOutputStream mOut;
    private Listener mListener;
    private boolean isRead;
    private boolean isSending;
    private BufferedInputStream inputStream = null;
    private OutputStream outputStream = null;

    BtBase(Listener listener) {
        mListener = listener;
    }

    /**
     * 循环读取对方数据(若没有数据，则阻塞等待)
     */
    void loopReadFile(BluetoothSocket socket) {
        mSocket = socket;
        try {
            if (!mSocket.isConnected()) mSocket.connect();
            notifyUI(Listener.CONNECTED, mSocket.getRemoteDevice());

            mOut = new DataOutputStream(mSocket.getOutputStream());
            DataInputStream in = new DataInputStream(mSocket.getInputStream());
            inputStream = new BufferedInputStream(mSocket.getInputStream());
            isRead = true;
            byte[] buffer = new byte[1024 * 2];
            StringBuilder sb = new StringBuilder();

            // 死循环读取
            while (isRead) {
                switch (in.readInt()) {
                    // 读取到短消息
                    case FLAG_MSG:
                        if (inputStream.available() != 0) {
                            int bytes = inputStream.read(buffer);
                            byte[] by = Arrays.copyOf(buffer, bytes); //存放实际读取的数据内容
                            Log.e(TAG, "ConnectedThread:run-->收到消息,长度" + by.length + "->" + bytes2HexString(by, by.length));  //16进制字符串
                            sb.append(bytes2HexString(by, by.length));
                            notifyUI(Listener.MSG, "接收短消息：" + sb.toString());
                        }
                        break;
                    // 读取到文件
                    case FLAG_FILE:
                        Util.mkdirs(FILE_PATH);
                        String fileName = in.readUTF(); //文件名
                        long fileLen = in.readLong();   //文件长度
                        // 读取文件内容
                        long len = 0;
                        int r;
                        byte[] b = new byte[4 * 1024];
                        FileOutputStream out = new FileOutputStream(FILE_PATH + fileName);
                        notifyUI(Listener.MSG, "正在接收文件(" + fileName + "),请稍后...");
                        while ((r = in.read(b)) != -1) {
                            out.write(b, 0, r);
                            len += r;
                            if (len >= fileLen)
                                break;
                        }
                        notifyUI(Listener.MSG, "文件接收完成(存放在:" + FILE_PATH + ")");
                        break;
                }
            }
        } catch (Throwable e) {
            e.printStackTrace();
            close();
        }
    }

    /**
     * 循环读取对方数据(若没有数据，则阻塞等待)
     */
    void loopRead(BluetoothSocket socket) {
        mSocket = socket;
        try {
            if (!mSocket.isConnected()) mSocket.connect();
            notifyUI(Listener.CONNECTED, mSocket.getRemoteDevice());

            inputStream = new BufferedInputStream(mSocket.getInputStream());
            isRead = true;
            byte[] buffer = new byte[1024 * 2];

            // 死循环读取
            while (isRead) {
                SystemClock.sleep(50);
                StringBuilder sb = new StringBuilder();
                int bytes = inputStream.read(buffer);
                byte[] by = Arrays.copyOf(buffer, bytes); //存放实际读取的数据内容
                Log.e(TAG, "ConnectedThread:run-->收到消息,长度" + by.length + "->" + bytes2HexString(by, by.length));  //16进制字符串
                sb.append(bytes2HexString(by, by.length));
                notifyUI(Listener.MSG, sb.toString());
            }
        } catch (Throwable e) {
            e.printStackTrace();
            close();
        }
    }

    /**
     * 发送短消息
     */
    public void sendMsg(byte[] msg) {
        if (checkSend()) return;
        isSending = true;
        try {
            if (null != mSocket)
                mOut = new DataOutputStream(mSocket.getOutputStream());
            mOut.writeInt(FLAG_MSG); //消息标记
            mOut.write(msg);
            mOut.flush();
            notifyUI(Listener.MSG, "发送短消息：" + bytes2HexString(msg, msg.length));
        } catch (Throwable e) {
            e.printStackTrace();
            close();
        }
        isSending = false;
    }

    /**
     * 发送短消息
     */
    public void sendData(byte[] msg) {
        if (checkSend()) return;
        isSending = true;
        try {
            if (null != mSocket)
                outputStream = mSocket.getOutputStream();
            outputStream.write(msg);
            outputStream.flush();
            Log.e(TAG, "发送短消息：" + bytes2HexString(msg, msg.length));  //16进制字符串
        } catch (Throwable e) {
            close();
        }
        isSending = false;
    }

    /**
     * 发送文件
     */
    public void sendFile(final String filePath) {
        if (checkSend()) return;

        if (TextUtils.isEmpty(filePath)) {
            Log.e(TAG, "文件路径为空");
            return;
        }

        isSending = true;
        Util.EXECUTOR.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    FileInputStream in = new FileInputStream(filePath);
                    File file = new File(filePath);
                    mOut.writeInt(FLAG_FILE);      //文件标记
                    mOut.writeUTF(file.getName()); //文件名
                    mOut.writeLong(file.length()); //文件长度
                    int r;
                    byte[] b = new byte[4 * 1024];
                    notifyUI(Listener.MSG, "正在发送文件(" + filePath + "),请稍后...");
                    while ((r = in.read(b)) != -1) mOut.write(b, 0, r);
                    mOut.flush();
                    notifyUI(Listener.MSG, "文件发送完成.");
                } catch (Throwable e) {
                    e.printStackTrace();
                    close();
                }
                isSending = false;
            }
        });
    }

    /**
     * 释放监听引用(例如释放对Activity引用，避免内存泄漏)
     */
    public void unListener() {
        mListener = null;
    }

    /**
     * 关闭Socket连接
     */
    public void close() {
        try {
            isRead = false;
            mSocket.close();
            notifyUI(Listener.DISCONNECTED, null);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    /**
     * 当前设备与指定设备是否连接
     */
    public boolean isConnected(BluetoothDevice dev) {
        boolean connected = (mSocket != null && mSocket.isConnected());
        if (dev == null) return connected;
        return connected && mSocket.getRemoteDevice().equals(dev);
    }

    // ============================================通知UI===========================================================
    private boolean checkSend() {
        if (isSending) {
            Log.e(TAG, "正在发送其它数据,请稍后再发...");
            return true;
        }
        return false;
    }

    private void notifyUI(final int state, final Object obj) {
        try {
            if (mListener != null)
                mListener.socketNotify(state, obj);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    public interface Listener {
        int DISCONNECTED = 0;
        int CONNECTED = 1;
        int MSG = 2;

        void socketNotify(int state, Object obj);
    }

    /**
     * 字节数组-->16进制字符串
     *
     * @param b      字节数组
     * @param length 字节数组长度
     * @return 16进制字符串 有空格类似“0A D5 CD 8F BD E5 F8”
     */
    private static String bytes2HexString(byte[] b, int length) {
        StringBuilder result = new StringBuilder();
        String hex;
        for (int i = 0; i < length; i++) {
            hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            result.append(hex.toUpperCase());
        }
        return result.toString();
    }

}
